package com.git.contractmanagement.service.impl;

import com.git.contractmanagement.entity.Contract;
import com.git.contractmanagement.entity.UserFavorite;
import com.git.contractmanagement.exception.BusinessException;
import com.git.contractmanagement.repository.ContractRepository;
import com.git.contractmanagement.repository.UserFavoriteRepository;
import jakarta.persistence.criteria.Predicate;
import jakarta.transaction.Transactional;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

@Service
@Transactional
public class ContractService {

    @Autowired
    private ContractRepository contractRepository;

    @Autowired
    private UserFavoriteRepository userFavoriteRepository;

    @Value("${file.upload-dir}")
    private String uploadDir;

    @Value("${file.preview-dir}")
    private String previewDir;

    @Value("${file.server-url}")
    private String fileServerUrl;

    // 创建合同
    public Contract createContract(Contract contract) {
        if (contract.getUploadTime() == null) {
            contract.setUploadTime(LocalDateTime.now());
        }

        // 初始化计数字段
        contract.setDownloadCount(contract.getDownloadCount() != null ? contract.getDownloadCount() : 0);
        contract.setFavoriteCount(contract.getFavoriteCount() != null ? contract.getFavoriteCount() : 0);
        contract.setPreviewCount(contract.getPreviewCount() != null ? contract.getPreviewCount() : 0);

        // 正确处理文件路径 - 无论pdfUrl是否为空，只要提供了fileId就应该设置pdfUrl
        if (contract.getFileId() != null && !contract.getFileId().isEmpty()) {
            contract.setPdfUrl(Paths.get(uploadDir, contract.getFileId()).toString());
        }

        return contractRepository.save(contract);
    }

    // 删除合同 - 修改：分离文件删除和数据库删除逻辑
    public void deleteContract(Integer id) {
        if (id == null) {
            throw new IllegalArgumentException("合同ID不能为空");
        }

        Contract contract = contractRepository.findById(id).orElse(null);
        if (contract == null) {
            System.out.println("尝试删除不存在的合同，ID: " + id);
            return;
        }

        // 先尝试删除相关文件，记录错误但不中断流程
        boolean filesDeleted = deleteContractFiles(contract);
        if (!filesDeleted) {
            System.err.println("删除合同 " + id + " 的相关文件时部分失败，但仍继续删除数据库记录。");
        }

        // 执行数据库删除
        try {
            contractRepository.deleteById(id);
            System.out.println("成功从数据库删除合同，ID: " + id);
        } catch (Exception e) {
            System.err.println("数据库删除合同失败: " + e.getMessage());
            e.printStackTrace();
            throw new RuntimeException("无法删除合同，可能由于存在关联数据：" + e.getMessage(), e);
        }
    }

    // 专门用于删除合同文件的方法
    private boolean deleteContractFiles(Contract contract) {
        boolean success = true;

        // 删除PDF文件
        if (contract.getPdfUrl() != null && !contract.getPdfUrl().isEmpty()) {
            Path pdfPath = null;
            try {
                pdfPath = Paths.get(contract.getPdfUrl()).normalize();
                if (Files.exists(pdfPath)) {
                    Files.delete(pdfPath);
                    System.out.println("成功删除PDF文件: " + pdfPath.toString());
                } else {
                    System.out.println("PDF文件不存在，跳过删除: " + pdfPath.toString());
                }
            } catch (Exception e) {
                System.err.println("删除PDF文件时出错，路径: " + (pdfPath != null ? pdfPath.toString() : "null") + ", 错误: " + e.getMessage());
                success = false;
            }
        }

        // 删除预览图片文件
        if (contract.getFileId() != null && !contract.getFileId().isEmpty()) {
            try {
                Path previewDirPath = Paths.get(previewDir).normalize();
                String fileIdWithoutExtension = contract.getFileId();
                if (contract.getFileId().lastIndexOf('.') > 0) {
                    fileIdWithoutExtension = contract.getFileId().substring(0, contract.getFileId().lastIndexOf('.'));
                }
                String previewFileName = "preview_" + fileIdWithoutExtension + ".png";
                Path previewPath = previewDirPath.resolve(previewFileName).normalize();

                if (Files.exists(previewPath)) {
                    System.out.println("找到预览图片，准备删除: " + previewPath.toString());
                    Files.delete(previewPath);
                    System.out.println("成功删除预览图片: " + previewPath.toString());
                } else {
                    System.out.println("预览图片不存在: " + previewPath.toString());
                    // 尝试替代方案
                    String alternativePreviewFileName = "preview_" + contract.getFileId();
                    if (!alternativePreviewFileName.endsWith(".png")) {
                        alternativePreviewFileName += ".png";
                    }
                    Path alternativePreviewPath = previewDirPath.resolve(alternativePreviewFileName).normalize();
                    if (Files.exists(alternativePreviewPath)) {
                        System.out.println("找到替代预览图片，准备删除: " + alternativePreviewPath.toString());
                        Files.delete(alternativePreviewPath);
                        System.out.println("成功删除替代预览图片: " + alternativePreviewPath.toString());
                    } else {
                        System.out.println("替代预览图片也不存在: " + alternativePreviewPath.toString());
                    }
                }
            } catch (Exception e) {
                System.err.println("删除预览图片时出错: " + e.getMessage());
                e.printStackTrace();
                success = false;
            }
        }

        return success;
    }

    // 更新合同
    public Contract updateContract(Integer id, Contract contractDetails) {
        Contract existing = getExistingContract(id);
        existing.setName(contractDetails.getName());
        existing.setCategory(contractDetails.getCategory());
        existing.setDescription(contractDetails.getDescription());
        // 确保设置了支付金额，即使为null也要更新
        existing.setPayAmount(contractDetails.getPayAmount());

        if (contractDetails.getFileId() != null) {
            existing.setFileId(contractDetails.getFileId());
            existing.setFileName(contractDetails.getFileName());
            existing.setPdfUrl(Paths.get(uploadDir, contractDetails.getFileId()).toString());
            // 不在这里设置 imgUrl，由 handleFileUpload 或其他方法处理
        }

        return contractRepository.save(existing);
    }

    // 根据ID查询单个合同
    public Optional<Contract> getById(Integer id) {
        return contractRepository.findById(id);
    }

    // 查询合同（分页、关键字、分类）
    public Page<Contract> searchContracts(String keyword, String category, Pageable pageable) {
        Specification<Contract> spec = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            if (StringUtils.hasText(keyword)) {
                String keywordPattern = "%" + keyword + "%";
                predicates.add(cb.or(
                        cb.like(root.get("name"), keywordPattern),
                        cb.like(root.get("description"), keywordPattern),
                        cb.like(root.get("category"), keywordPattern)
                ));
            }
            if (StringUtils.hasText(category)) {
                predicates.add(cb.equal(root.get("category"), category));
            }

            return cb.and(predicates.toArray(new Predicate[0]));
        };

        return contractRepository.findAll(spec, pageable);
    }

    // 文件上传处理（新建或编辑时上传） - 修改：明确职责，生成预览图
    public Contract handleFileUpload(Integer id, MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new BusinessException("上传的文件为空");
        }

        Contract contract = getExistingContract(id);
        Path uploadDirPath = Paths.get(uploadDir);
        Path previewDirPath = Paths.get(previewDir);

        try {
            // 生成存储路径
            String pdfFilename = generateUniqueFilename(file.getOriginalFilename());
            Path pdfPath = uploadDirPath.resolve(pdfFilename);

            // 核心安全校验
            if (!pdfPath.startsWith(uploadDirPath.normalize())) {
                throw new BusinessException("文件路径不合法");
            }

            Files.createDirectories(uploadDirPath);
            Files.write(pdfPath, file.getBytes());

            // 生成预览图
            String previewFilename = generatePreviewImage(file, pdfFilename);
            Path previewPath = previewDirPath.resolve(previewFilename);

            // 更新合同信息
            contract.setPdfUrl(pdfPath.toString());
            contract.setFileId(pdfFilename);
            contract.setImgUrl(previewPath.toString()); // 设置预览图路径

            return contractRepository.save(contract);
        } catch (IOException e) {
            throw new BusinessException("文件处理失败: " + e.getMessage());
        }
    }

    // 文件下载处理
    public byte[] downloadPdf(Integer id) {
        Contract contract = getExistingContract(id);
        try {
            Path pdfPath = Paths.get(contract.getPdfUrl());
            return Files.readAllBytes(pdfPath);
        } catch (IOException e) {
            throw new BusinessException("文件读取失败: " + e.getMessage());
        }
    }

    // 预览图片实现
    public byte[] previewImage(Integer id) {
        Contract contract = getExistingContract(id);
        Path imgPath = getValidPreviewPath(contract);

        if (imgPath == null) {
            return generateDefaultPreviewImage("暂无预览图");
        }

        try {
            return Files.readAllBytes(imgPath);
        } catch (IOException e) {
            throw new BusinessException("预览图读取失败: " + e.getMessage());
        }
    }

    // 获取有效的预览图路径
    private Path getValidPreviewPath(Contract contract) {
        Path previewDirPath = Paths.get(previewDir);

        // 情况1：已有预览图且存在
        if (StringUtils.hasText(contract.getFileId())) {
            String previewName = "preview_" + contract.getFileId();
            if (!previewName.endsWith(".png")) {
                previewName += ".png";
            }
            Path imgPath = previewDirPath.resolve(previewName);
            if (Files.exists(imgPath)) {
                return imgPath;
            }
        }

        // 情况2：无预览图但有PDF，尝试生成
        if (StringUtils.hasText(contract.getFileId())) {
            Path pdfPath = Paths.get(uploadDir, contract.getFileId());
            if (Files.exists(pdfPath)) {
                try {
                    // 修改：调用新方法，获取完整路径
                    Path generatedPreviewPath = regeneratePreviewImageAndGetPath(pdfPath.toString(), contract.getFileId());
                    contract.setImgUrl(generatedPreviewPath.toString()); // 更新合同的imgUrl
                    contractRepository.save(contract);
                    return generatedPreviewPath;
                } catch (Exception e) {
                    throw new BusinessException("预览图生成失败: " + e.getMessage());
                }
            }
        }

        return null;
    }

    // 从文件重新生成预览图的方法 - 修改：返回完整路径
    private Path regeneratePreviewImageAndGetPath(String pdfFilePath, String pdfFilename) throws IOException {
        Path previewDirPath = Paths.get(previewDir);
        Files.createDirectories(previewDirPath);

        try (PDDocument document = PDDocument.load(new File(pdfFilePath))) {
            PDFRenderer pdfRenderer = new PDFRenderer(document);
            BufferedImage bufferedImage = pdfRenderer.renderImageWithDPI(0, 150);

            String nameWithoutExtension = pdfFilename.lastIndexOf('.') > 0 ?
                    pdfFilename.substring(0, pdfFilename.lastIndexOf('.')) : pdfFilename;
            String previewName = "preview_" + nameWithoutExtension + ".png";
            Path previewPath = previewDirPath.resolve(previewName);

            ImageIO.write(bufferedImage, "png", previewPath.toFile());
            System.out.println("预览图重新生成成功: " + previewPath.toString());

            return previewPath; // 返回完整路径
        } catch (IOException e) {
            System.err.println("PDF文件处理失败，可能是文件已损坏或不是有效的PDF格式: " + e.getMessage());
            e.printStackTrace();
            String errorMsg = e.getMessage();
            if (errorMsg != null && errorMsg.contains("Header doesn't contain versioninfo")) {
                throw new IOException("上传的文件不是有效的PDF文件，请确保上传的是真正的PDF文件", e);
            }
            throw new IOException("PDF文件处理失败，可能是文件已损坏或不是有效的PDF格式: " + e.getMessage(), e);
        } catch (Exception e) {
            System.err.println("预览图重新生成过程中发生未知错误: " + e.getMessage());
            e.printStackTrace();
            throw new IOException("预览图重新生成过程中发生未知错误: " + e.getMessage(), e);
        }
    }

    // 生成默认预览图的方法
    public byte[] generateDefaultPreviewImage(String message) {
        try {
            BufferedImage defaultImage = new BufferedImage(400, 300, BufferedImage.TYPE_INT_RGB);
            Graphics2D graphics = defaultImage.createGraphics();
            graphics.setColor(Color.LIGHT_GRAY);
            graphics.fillRect(0, 0, 400, 300);
            graphics.setColor(Color.GRAY);
            graphics.setFont(new Font("SansSerif", Font.BOLD, 20));
            FontMetrics fm = graphics.getFontMetrics();
            int x = (400 - fm.stringWidth(message)) / 2;
            int y = 300 / 2;
            graphics.drawString(message, x, y);
            graphics.dispose();

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(defaultImage, "png", baos);
            return baos.toByteArray();
        } catch (IOException e) {
            System.err.println("生成默认预览图失败: " + e.getMessage());
            e.printStackTrace();
            BufferedImage errorImage = new BufferedImage(400, 300, BufferedImage.TYPE_INT_RGB);
            Graphics2D g = errorImage.createGraphics();
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, 400, 300);
            g.dispose();

            try {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ImageIO.write(errorImage, "png", baos);
                return baos.toByteArray();
            } catch (IOException ioException) {
                return new byte[0];
            }
        }
    }

    // 生成唯一文件名
    private String generateUniqueFilename(String originalFilename) {
        if (originalFilename == null || originalFilename.isEmpty()) {
            originalFilename = "unnamed_file.pdf";
        }

        String extension = "";
        if (originalFilename.lastIndexOf(".") != -1) {
            extension = originalFilename.substring(originalFilename.lastIndexOf("."));
        } else {
            extension = ".pdf";
        }
        return UUID.randomUUID().toString() + extension;
    }

    // PDF转图片方法 - 使用Apache PDFBox实现
    private String generatePreviewImage(MultipartFile file, String pdfFilename) throws IOException {
        Path previewDirPath = Paths.get(previewDir);
        Files.createDirectories(previewDirPath);

        try {
            PDDocument document = PDDocument.load(file.getInputStream());
            PDFRenderer pdfRenderer = new PDFRenderer(document);
            BufferedImage bufferedImage = pdfRenderer.renderImageWithDPI(0, 150);

            String fileId = pdfFilename.lastIndexOf('.') > 0 ?
                    pdfFilename.substring(0, pdfFilename.lastIndexOf('.')) : pdfFilename;
            String previewName = "preview_" + fileId + ".png";
            Path previewPath = previewDirPath.resolve(previewName);

            ImageIO.write(bufferedImage, "png", previewPath.toFile());
            System.out.println("预览图生成成功: " + previewPath.toString());
            document.close();

            return previewName;
        } catch (IOException e) {
            System.err.println("PDF文件处理失败，可能是文件已损坏或不是有效的PDF格式: " + e.getMessage());
            e.printStackTrace();
            String errorMsg = e.getMessage();
            if (errorMsg != null && errorMsg.contains("Header doesn't contain versioninfo")) {
                throw new IOException("上传的文件不是有效的PDF文件，请确保上传的是真正的PDF文件", e);
            }
            throw new IOException("PDF文件处理失败，可能是文件已损坏或不是有效的PDF格式: " + e.getMessage(), e);
        } catch (Exception e) {
            System.err.println("预览图生成过程中发生未知错误: " + e.getMessage());
            e.printStackTrace();
            throw new IOException("预览图生成过程中发生未知错误: " + e.getMessage(), e);
        }
    }

    // 增加下载次数
    public int increaseDownloadCount(Integer id) {
        try {
            Contract contract = getExistingContract(id);
            Integer newCount = (contract.getDownloadCount() == null ? 0 : contract.getDownloadCount()) + 1;
            contract.setDownloadCount(newCount);
            contractRepository.save(contract);
            return newCount;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException("增加下载次数失败: " + e.getMessage());
        }
    }

    // 增加预览次数
    public int increasePreviewCount(Integer id) {
        try {
            Contract contract = getExistingContract(id);
            Integer newCount = (contract.getPreviewCount() == null ? 0 : contract.getPreviewCount()) + 1;
            contract.setPreviewCount(newCount);
            contractRepository.save(contract);
            return newCount;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException("增加预览次数失败: " + e.getMessage());
        }
    }

    // 获取所有合同分类
    public List<String> getAllCategories() {
        List<String> categories = new ArrayList<>();
        categories.add("劳动用工");
        categories.add("商业合作");
        categories.add("金融借贷");
        categories.add("房产交易");
        return categories;
    }

    // 获取合同统计信息
    public ContractStats getContractStats() {
        long totalContracts = contractRepository.count();
        int totalDownloads = 0;
        int totalFavorites = 0;
        int totalPreviews = 0;

        List<Contract> allContracts = contractRepository.findAll();
        for (Contract contract : allContracts) {
            totalDownloads += (contract.getDownloadCount() == null ? 0 : contract.getDownloadCount());
            totalFavorites += (contract.getFavoriteCount() == null ? 0 : contract.getFavoriteCount());
            totalPreviews += (contract.getPreviewCount() == null ? 0 : contract.getPreviewCount());
        }

        return new ContractStats(totalContracts, totalDownloads, totalFavorites, totalPreviews);
    }

    // 辅助方法：转换合同中的本地文件路径为HTTP URL
    private Contract convertLocalPathsToHttpUrls(Contract contract) {
        if (contract.getImgUrl() != null && !contract.getImgUrl().isEmpty()) {
            // 将本地文件路径转换为HTTP URL
            contract.setImgUrl(fileServerUrl + "/" + contract.getId() + "/preview");
        } else if (contract.getFileId() != null && !contract.getFileId().isEmpty()) {
            // 如果没有预览图但有文件ID，则也设置预览URL
            contract.setImgUrl(fileServerUrl + "/" + contract.getId() + "/preview");
        }

        if (contract.getPdfUrl() != null && !contract.getPdfUrl().isEmpty()) {
            contract.setPdfUrl(fileServerUrl + "/" + contract.getId() + "/download");
        }

        return contract;
    }

    // 私有辅助方法：获取已存在的合同，不存在则抛出异常
    private Contract getExistingContract(Integer id) {
        return contractRepository.findById(id)
                .orElseThrow(() -> new BusinessException("合同不存在: " + id));
    }

    // 新增：保存单个文件的方法 - 修改：不生成预览图，职责单一
    public String saveFile(MultipartFile file) throws IOException {
        try {
            String uniqueFileName = generateUniqueFilename(file.getOriginalFilename());
            System.out.println("生成的文件名: " + uniqueFileName);

            Path uploadDirPath = Paths.get(uploadDir);
            System.out.println("上传目录路径: " + uploadDirPath);
            Files.createDirectories(uploadDirPath);

            Path filePath = uploadDirPath.resolve(uniqueFileName);
            System.out.println("文件保存路径: " + filePath);

            if (!filePath.startsWith(uploadDirPath)) {
                throw new BusinessException("文件保存路径不合法");
            }

            Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
            System.out.println("文件保存成功: " + filePath);

            return uniqueFileName; // 只返回文件名
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException("文件保存失败: " + e.getMessage());
        }
    }

    // 新增：获取用户收藏的合同列表
    public List<Contract> getUserFavorites(Integer userId) {
        System.out.println("getUserFavorites called with userId: " + userId);
        // 确保返回空列表而不是 null
        List<UserFavorite> userFavorites = userFavoriteRepository.findByUserIdAndFavoriteStatus(userId, 1);
        System.out.println("Found " + (userFavorites != null ? userFavorites.size() : 0) + " favorite records");
        
        if (userFavorites == null || userFavorites.isEmpty()) {
            return new ArrayList<>(); // 明确返回空列表
        }

        List<Integer> contractIds = new ArrayList<>();
        for (UserFavorite fav : userFavorites) {
            if (!contractIds.contains(fav.getContractId())) {
                contractIds.add(fav.getContractId());
            }
        }
        
        System.out.println("Contract IDs to fetch: " + contractIds);

        if (contractIds.isEmpty()) {
            return new ArrayList<>();
        }

        List<Contract> contracts = contractRepository.findAllById(contractIds);
        System.out.println("Found " + contracts.size() + " contracts");
        
        for (Contract contract : contracts) {
            if (contract.getFavoriteCount() == null) {
                contract.setFavoriteCount(0);
            }
            System.out.println("Contract: " + contract.getId() + " - " + contract.getName() + ", favoriteCount: " + contract.getFavoriteCount());
        }

        return contracts;
    }

    // 新增：切换收藏状态
    public Contract toggleFavorite(Integer contractId, Integer userId, Boolean favorite) {
        System.out.println("toggleFavorite called with contractId: " + contractId + ", userId: " + userId + ", favorite: " + favorite);
        
        // 查找现有的收藏记录
        List<UserFavorite> existingFavorites = userFavoriteRepository.findByUserIdAndContractId(userId, contractId);
        UserFavorite userFavorite = existingFavorites.isEmpty() ? null : existingFavorites.get(0);
        
        Contract contract = contractRepository.findById(contractId)
            .orElseThrow(() -> new BusinessException("合同不存在"));
        
        System.out.println("Found contract: " + contract.getName() + ", current favoriteCount: " + contract.getFavoriteCount());
        
        if (favorite) {
            // 收藏操作
            if (userFavorite == null) {
                // 创建新的收藏记录
                userFavorite = new UserFavorite();
                userFavorite.setUserId(userId);
                userFavorite.setContractId(contractId);
                userFavorite.setFavoriteStatus(1);
                userFavoriteRepository.save(userFavorite);
                System.out.println("Created new favorite record");
                
                // 增加合同的收藏计数
                int newCount = contract.getFavoriteCount() == null ? 1 : contract.getFavoriteCount() + 1;
                contract.setFavoriteCount(newCount);
                System.out.println("Increased favorite count to: " + newCount);
            } else if (userFavorite.getFavoriteStatus() != 1) {
                // 如果记录存在但状态不是收藏，则更新状态
                userFavorite.setFavoriteStatus(1);
                userFavoriteRepository.save(userFavorite);
                System.out.println("Updated existing favorite record status to 1");
                
                // 增加合同的收藏计数
                int newCount = contract.getFavoriteCount() == null ? 1 : contract.getFavoriteCount() + 1;
                contract.setFavoriteCount(newCount);
                System.out.println("Increased favorite count to: " + newCount);
            } else {
                System.out.println("Already favorited, incrementing count anyway");
                // 为确保计数正确，即使已收藏也增加计数
                int newCount = contract.getFavoriteCount() == null ? 1 : contract.getFavoriteCount() + 1;
                contract.setFavoriteCount(newCount);
                System.out.println("Increased favorite count to: " + newCount);
            }
        } else {
            // 取消收藏操作
            if (userFavorite != null && userFavorite.getFavoriteStatus() == 1) {
                userFavorite.setFavoriteStatus(0);
                userFavoriteRepository.save(userFavorite);
                System.out.println("Updated favorite record status to 0");
                
                // 减少合同的收藏计数
                int newCount = Math.max(0, (contract.getFavoriteCount() == null ? 0 : contract.getFavoriteCount()) - 1);
                contract.setFavoriteCount(newCount);
                System.out.println("Decreased favorite count to: " + newCount);
            }
        }
        
        // 保存合同更新到数据库
        Contract savedContract = contractRepository.save(contract);
        System.out.println("Saved contract with favoriteCount: " + savedContract.getFavoriteCount());
        return savedContract;
    }

    // 统计信息内部类
    public static class ContractStats {
        private long totalContracts;
        private int totalDownloads;
        private int totalFavorites;
        private int totalPreviews;

        public ContractStats(long totalContracts, int totalDownloads, int totalFavorites, int totalPreviews) {
            this.totalContracts = totalContracts;
            this.totalDownloads = totalDownloads;
            this.totalFavorites = totalFavorites;
            this.totalPreviews = totalPreviews;
        }

        public long getTotalContracts() { return totalContracts; }
        public int getTotalDownloads() { return totalDownloads; }
        public int getTotalFavorites() { return totalFavorites; }
        public int getTotalPreviews() { return totalPreviews; }
    }
}